package com.example.eventbustest

import android.os.Handler
import android.os.Looper
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.LinkedBlockingQueue
import kotlin.collections.ArrayList
import kotlin.collections.HashMap

class MyEventBus {
    //记录这个类型的对象有哪些注册龙的方法
    private val subscribeMethodsMap: HashMap<Class<*>, ArrayList<MySubscriberMethod>> = HashMap()

    //记录所有观察者,可能有一个class的多个实例
    private val subscribes: ArrayList<MySubscription> = ArrayList()

    //通过eventType记录的观察者map
    private val eventTypeSubscribeMap: HashMap<Class<*>, CopyOnWriteArrayList<MySubscription>> =
        HashMap()

    companion object {
        val instance: MyEventBus by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            MyEventBus()
        }
        private const val TAG = "MY_TAG_MyEventBus"
        private val handler = Handler(Looper.getMainLooper())
    }

    fun register(subscribe: Any) {
        val clazz = subscribe::class.java
        //已经注册过，直接返回
        if (subscribes.contains(subscribe)) {
            return
        }
        val subscribeMethods = getSubscribeMethods(clazz)
        if (subscribeMethods.isEmpty()) {
            return
        }
        //如果这个类没有注册过才需要注册
        for (method in subscribeMethods) {
            subscribes.add(MySubscription(subscribe, method))
        }
        //更新通过event类型查找观察者的map
        var eventTypeValue: CopyOnWriteArrayList<MySubscription>?
        for (method in subscribeMethods) {
            eventTypeValue = eventTypeSubscribeMap[method.eventType]
            if (eventTypeValue == null) {
                eventTypeValue = CopyOnWriteArrayList()
            }
            eventTypeValue.add(MySubscription(subscribe, method))
            eventTypeSubscribeMap[method.eventType] = eventTypeValue
        }
    }

    fun unregister(subscribe: Any) {
        val clazz = subscribe::class.java
        //先从观察者中移除
        for (item in subscribes) {
            if (item.subscribe == subscribe) {
                subscribes.remove(item)
            }
        }
        //再检查还有没有这个类型的实例观察者，如果没有，则将这个类型的方法注销掉
        var isExist = false
        for (item in subscribes) {
            if (item.subscribe::class.java == clazz) {
                isExist = true
                break
            }
        }
        if (!isExist) {
            subscribeMethodsMap.remove(clazz)
        }

        //更新通过event类型查找观察者的map
        //1.获取这个观察者的所有event类型
        //2.更新
        val methods = subscribeMethodsMap[clazz]
        methods?.apply {
            for (method in methods) {
                val subscribes = eventTypeSubscribeMap[method.eventType]
                subscribes?.apply {
                    remove(subscribe)
                    if (size == 0) {
                        eventTypeSubscribeMap.remove(method.eventType)
                    }
                }
            }
        }
    }

    // main thread
    fun post(event: Any) {
        val clazz = event::class.java
        //根据event的类型获取观察者的列表
        val subscribeList = eventTypeSubscribeMap[clazz] ?: return
        var i = 0
        val isMainThread = isMainThread()
        while (i < subscribeList.size) {
            if (isMainThread) {
                if (subscribeList[i].method.threadMode == MyThreadMode.MAIN) {
                    invokeMethod(subscribeList[i], event)
                } else {
                    ChildThreadPost.instance.post(subscribeList[i], event)
                }
            } else {
                if (subscribeList[i].method.threadMode == MyThreadMode.MAIN) {
                    MainThreadPoster.instance.post(subscribeList[i], event)
                } else {
                    invokeMethod(subscribeList[i], event)
                }
            }
            i++
        }
    }

    private fun isMainThread(): Boolean {
        return Looper.myLooper() == Looper.getMainLooper()
    }

    private fun invokeMethod(item: MySubscription, event: Any) {
        item.method.method.invoke(item.subscribe, event)
    }

    //获取这个类的所有event方法，如果这个类的方法已经存在，则直接返回
    private fun getSubscribeMethods(clazz: Class<*>): List<MySubscriberMethod> {
        val list = ArrayList<MySubscriberMethod>()
        if (subscribeMethodsMap[clazz] != null) {
            return subscribeMethodsMap[clazz]!!
        }
        for (method in clazz.declaredMethods) {
            val annotation = method.getDeclaredAnnotation(MySubscribe::class.java)
            if (annotation != null) {
                if (method.parameterCount != 1) {
                    throw Exception("The parameter need only one!")
                }
                list.add(
                    MySubscriberMethod(
                        method,
                        method.parameters[0].type,
                        annotation.threadMode
                    )
                )
            }
        }
        subscribeMethodsMap[clazz] = list
        return list
    }

}